unit u_server;

interface

uses
  IdTCPServer,
  IdTCPClient,
  IdContext,
  idhttp,
  u_jresau,
  IdTCPConnection,
  u_font,
  classes,
  sysutils,
  u_thread_ecoute;

type

  C_server = class
  private

    server : TIdTCPServer;
    client : TIdTCPClient;
    f_name : string;
    nick : string;
    client_list : Array of string;
    thread_ecoute : ecoute;
    locked : boolean;
    procedure ServerExecute (AContext: TIdContext);
    procedure ServerConnect (AContext: TIdContext);
    procedure ServerDisconnect (AContext: TIdContext);
    function is_client(nick : string) : boolean;

    public

    procedure serverstop;
    procedure connectserver(port_ : integer; nick_ : string; map_name : string);
    procedure connectclient(port_ : integer; host_, nick_ : string);
    constructor create;
    procedure Dispose;

    //Fonctions pour les clients
    procedure msg_client(msg : string);
    procedure new_posclient(p1, p2, p3, p4, p5, p6 : string);
    procedure send_hitennemi(p1, p2, p3, p4, p5, p6, p7 : string);
    procedure send_del_obj_client(p1, p2, p3 : string);

    //Procedure pout le serveur :
    procedure send_del_client(_name : string);
    procedure Send_newpos_allclients(p1, p2, p3, p4, p5, p6 : string);
    procedure send_new_client(_x, _y, _z : integer;_name : string);
    procedure Send_msg_allclients(msg : string);
    procedure send_ennemi_move(p1, p2, p3, p4, p5, p6 : string);
    procedure send_ennemi_del_pos(p1, p2, p3 : string);
    procedure send_ennemi_del_ij(p1, p2 : string);
    procedure send_joueur_hit(p1, p2, p3, p4, p5, p6, p7 : string);
    procedure send_new_obj(p1, p2, p3, p4, p5, p6, p7, p8 : string);
    procedure send_del_obj(p1, p2, p3 : string);
    procedure send_new_ennemi(p1, p2, p3, p4, p5, p6 : string);



  end;

  TClientData = Class(Tobject)

    nickname : string;
  end;

implementation

uses
  u_engine;



constructor C_server.create;
  begin
    inherited create;
    //Prout!
    locked := false;
  end;





  //Creation du serveur
  procedure C_server.connectserver(port_: Integer;nick_: string; map_name : string);
    begin
      try
      f_name := map_name;
      server := TIdTCPServer.Create(nil);
      server.DefaultPort := port_;
      server.OnExecute := ServerExecute;
      server.OnDisconnect := ServerDisconnect;
      server.OnConnect := ServerConnect;
      server.Active := true;
      SetLength(client_list, 1);
      client_list[0] := nick_;
      except
        myplayer.mychat.add_text('Echec de la connexion');
      end;
      myplayer.mychat.add_text('**Serveur, créé sans souci**');
    end;

  procedure C_server.serverstop;
  var
    ClientsList: TList;
    i: integer;
    begin
      if not assigned(server) then
        Exit;
      Send_msg_allclients('Good bye le serveur vous quitte');
      Send_msg_allclients('&-' + Nick);
      ClientsList := Server.Contexts.LockList;
      Server.Contexts.UnlockList;
      for i:= 0 to ClientsList.Count -1 do
        TIdContext(ClientsList.Items[i]).Connection.Disconnect;
      //desactivation du serveur
////      Server.Active := False;
//
//      server.
//
//      server.Dispose;
//      server.Destroy;
//      ClientsList.Free;
    end;

  procedure C_server.connectclient(port_ : integer; host_, nick_ : string);
  var
    i, j : integer;
    buf : string;
    map_size : Integer;
    tmpmap : Textfile;
    begin
      client := TIdTCPClient.Create(nil);
      client.Host := host_;
      client.Port := port_;
      client.Connect;


      client.IOHandler.WriteLn(nick_);

      locked := true;

      if client.IOHandler.ReadLn = 'OK' then
        myplayer.mychat.add_text('OK de conection reçu!');

      AssignFile(tmpmap, 'titoujtecul.tmp');
      Rewrite(tmpmap);
      buf := client.IOHandler.ReadLn;
      while buf <> 'endomap' do
        begin
          Writeln(tmpmap, buf);
          buf := client.IOHandler.ReadLn;
        end;
      CloseFile(tmpmap);

      locked := false;

      myplayer.mychat.add_text(client.IOHandler.ReadLn);


      if not client.Connected then
        begin
          myplayer.mychat.add_text('Echec de la connexion');
          Exit;
        end;

      //Creation du thread d'éoute des messages
      thread_ecoute := ecoute.create(client);
      nick := nick_;
    end;

  procedure C_server.ServerConnect(AContext: TIdContext);
  var
    ClientNickName: String;
    ClientData: TClientData;
    i, j : integer;
    tmpmap : Textfile;
    buf : string;
    tab_play : t_player;
    begin
      locked := true;
      //Code coté serveur quand un client se connecte
      ClientNickName := AContext.Connection.IOHandler.ReadLn;
      if is_client(ClientNickName) then
        myplayer.mychat.add_text('client ajouté!')
        else
        begin
         //Ici on dit qu'au client il ne peut pas se connecter
          ClientData := TClientData.Create;
          AContext.Data := ClientData;
          AContext.Connection.Disconnect;
          Exit;
        end;

      AContext.Connection.IOHandler.WriteLn('OK');
      //Envoi de la map par le serveur
      AssignFile(tmpmap, f_name);
      Reset(tmpmap);

      while not Eof(tmpmap) do
        begin
          Readln(tmpmap, buf);
          AContext.Connection.IOHandler.WriteLn(buf);
        end;
      CloseFile(tmpmap);

      AContext.Connection.IOHandler.WriteLn('endomap');

      AContext.Connection.IOHandler.WriteLn('Yo tranquille t''es sur le serveur!');

      //Fin envoi de données

      //Envoi de la liste des clients connectés.
      myplayer.myreseau.get_all_info(tab_play);
      if Length(tab_play) <> 0 then
        begin
          for i := 0 to Length(tab_play) - 1 do
            begin
              AContext.Connection.IOHandler.WriteLn('#n');
              AContext.Connection.IOHandler.WriteLn(tab_play[i].name);
              AContext.Connection.IOHandler.WriteLn(IntToStr(tab_play[i].x));
              AContext.Connection.IOHandler.WriteLn(IntToStr(tab_play[i].y));
              AContext.Connection.IOHandler.WriteLn(IntToStr(tab_play[i].z));
            end;
        end;

      AContext.Connection.IOHandler.WriteLn('#n');
      AContext.Connection.IOHandler.WriteLn(myplayer.pseudo_);
      AContext.Connection.IOHandler.WriteLn(inttostr(myplayer.get_x));
      AContext.Connection.IOHandler.WriteLn(inttostr(myplayer.get_y));
      AContext.Connection.IOHandler.WriteLn(inttostr(myplayer.etage));

      locked := false;

      send_new_client(mymesh.dep_eta.x, mymesh.dep_eta.y,mymesh.dep_eta.etage, ClientNickName);

      myplayer.myreseau.add_player(mymesh.dep_eta.x, mymesh.dep_eta.y,mymesh.dep_eta.etage, ClientNickName);

      ClientData := TClientData.Create;
      ClientData.NickName := ClientNickName;
      AContext.Data := ClientData;
      //On ajoute le client à la liste des clients
      SetLength(client_list, length(client_list) + 1);
      client_list[Length(client_list) - 1] := ClientNickName;
      Send_msg_allclients(ClientNickName + ' : vient de se connecter');

    end;

  procedure C_server.ServerDisconnect(AContext: TIdContext);
  var
    ClientData : TClientData;
    i, j : integer;
    begin
      ClientData := TClientData(AContext.Data);
      i := 0;
      while (i < length(client_list)) and (ClientData.nickname <> client_list[i]) do
        i := i + 1;
      for j := i to length(client_list) - 2 do
        client_list[j] := client_list[j + 1];
      SetLength(client_list, length(client_list) - 1);
      send_del_client(ClientData.nickname);
      Send_msg_allclients(ClientData.NickName + ' : vient de se déconnecter');
      ClientData.Free;
      AContext.Data := nil;
    end;

  function C_server.is_client(nick : string) : boolean;
  var
    i : integer;
    begin
      i := 0;
      while (i < length(client_list)) and (client_list[i] <> nick) do
        i := i + 1;
      Result := (i = length(client_list));
    end;

  procedure c_server.Dispose;
    begin
    //
    end;

  procedure C_server.ServerExecute(AContext: TIdContext);
  var
    oldx, oldy, newx, newy, i : integer;
    msg, s1 : string;
    p1, p2, p3, p4, p5, p6, p7 : string;
    begin
//      myplayer.mychat.add_text('ServerExecute');
      msg := AContext.Connection.IOHandler.ReadLn;
      if msg = '#msg' then
        begin
          //Reception d'un msg
          s1 := AContext.Connection.IOHandler.ReadLn;
          Send_msg_allclients(s1);
        end
        else if msg = '#newoscli' then
          begin
            //Actualisation de la position d'un joueur
            p1 := AContext.Connection.IOHandler.ReadLn;
            p2 := AContext.Connection.IOHandler.ReadLn;
            p3 := AContext.Connection.IOHandler.ReadLn;
            p4 := AContext.Connection.IOHandler.ReadLn;
            p5 := AContext.Connection.IOHandler.ReadLn;
            p6 := Acontext.connection.IOHandler.Readln;
            myplayer.myreseau.change_pos(StrToInt(p1), StrToInt(p2), StrToInt(p3), StrToInt(p4), StrToInt(p5), StrToInt(p6));
            Send_newpos_allclients(p1, p2, p3, p4, p5, p6);
          end
          else if msg = '#delobj' then
            begin
              //Suppression d'un objet de la map
              p1 := (AContext.Connection.IOHandler.ReadLn);
              p2 := (AContext.Connection.IOHandler.ReadLn);
              p3 := (AContext.Connection.IOHandler.ReadLn);
              send_del_obj(p1,p2, p3);
              mymesh.suppr_obj(p1, p2, p3, mymesh.dep_eta.etage);
            end
            else if msg = '#hitennemi' then
              begin
                p1 := AContext.Connection.IOHandler.ReadLn;
                p2 := AContext.Connection.IOHandler.ReadLn;
                p3 := AContext.Connection.IOHandler.ReadLn;
                p4 := AContext.Connection.IOHandler.ReadLn;
                p5 := AContext.Connection.IOHandler.ReadLn;
                p6 := Acontext.connection.IOHandler.Readln;
                p7 := AContext.Connection.IOHandler.ReadLn;
                //Ajouter attaque d'ennemi + moteur à particule déclanché
              end;
    end;


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
  //Fonctions pour les clients//
  //////////////////////////////

  procedure C_server.msg_client(msg: string);
  var
    buf : string;
    begin
      try
        while locked do
          sleep(100);
        client.IOHandler.WriteLn('#msg');
        client.IOHandler.WriteLn(msg);
      except
        On E : Exception do
          myplayer.mychat.add_text('Erreur envoi msg_client: ' + E.message);
      end;
    end;

  procedure c_server.new_posclient(p1, p2, p3, p4, p5, p6 : string);
    begin
      try
        while locked do
          sleep(100);
        //thread_ecoute.Suspend;
        client.IOHandler.WriteLn('#newposcli');
        client.IOHandler.WriteLn(p1);
        client.IOHandler.WriteLn(p2);
        client.IOHandler.WriteLn(p3);
        client.IOHandler.WriteLn(p4);
        client.IOHandler.WriteLn(p5);
        client.IOHandler.WriteLn(p6);
      except
        On E : Exception do
          myplayer.mychat.add_text('Erreur new_posclient : ' + E.Message);
      end;
    end;

    procedure c_server.send_hitennemi(p1, p2, p3, p4, p5, p6, p7 : string);
    begin
      try
        try
      //    thread_ecoute.Suspend;
          while locked do
            sleep(100);
          client.IOHandler.WriteLn('#hitennemi');
          client.IOHandler.WriteLn(p1);
          client.IOHandler.WriteLn(p2);
          client.IOHandler.WriteLn(p3);
          client.IOHandler.WriteLn(p4);
          client.IOHandler.WriteLn(p5);
          client.IOHandler.WriteLn(p6);
          client.IOHandler.WriteLn(p7);
        except
          On E : Exception do
            myplayer.mychat.add_text('Erreur envoi msg_client: ' + E.message);
        end;
      finally
        //no fingue!
      end;
    end;

  procedure c_server.send_del_obj_client(p1, p2, p3 : string);
    begin
      try
        while locked do
          sleep(100);
        client.IOHandler.WriteLn('#delobj');
        client.IOHandler.WriteLn(p1);
        client.IOHandler.WriteLn(p2);
        client.IOHandler.WriteLn(p3);
      except
        On E : Exception do
          myplayer.mychat.add_text('Erreur envoi del_obj_client' + E.message);
      end;
    end;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
  //Fonctions pour le serveur//
  /////////////////////////////
  
  procedure C_server.Send_msg_allclients(msg : string);
  var
    i: integer;
    ClientsList: TList;
    begin
      try
        try
          while locked do
            sleep(100);
          ClientsList := server.Contexts.LockList;
          for i:=0 to ClientsList.Count -1 do
            begin
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn('#msg');
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn(Msg);
            end;
        Except
          On E:Exception do
          myplayer.mychat.add_text('Erreur send_msg_allclients: ' + E.Message);
        End;
      Finally
        Server.Contexts.UnlockList;
        myplayer.mychat.add_text(msg);
      end;
    end;

  procedure c_server.Send_newpos_allclients(p1, p2, p3, p4, p5, p6 : string);
  var
    i: integer;
    ClientsList: TList;
    begin
      try
        try
          while locked do
            sleep(100);
          ClientsList := server.Contexts.LockList;
          for i:=0 to ClientsList.Count -1 do
            begin
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn('#newposjoueur');
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn(p1);
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn(p2);
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn(p3);
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn(p4);
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn(p5);
            TIdContext(ClientsList.Items[i]).Connection.IOHandler.WriteLn(p6);
            end;
        Except
          On E:Exception do
          myplayer.mychat.add_text('Erreur send_newpos_allclients: ' + E.Message);
        End;
      Finally
        Server.Contexts.UnlockList;
      end;
    end;
    
  procedure C_server.send_new_client(_x, _y, _z : integer;_name : string);
  var
    Clist : TList;
    i : integer;
    begin
      try
        try
          while locked do
          sleep(100);
          CList := server.Contexts.LockList;
          for i := 0 to Clist.Count - 1 do
            begin
              TIdContext(Clist.Items[i]).Connection.IOHandler.WriteLn('#newclient');
              TIdContext(Clist.Items[i]).Connection.IOHandler.WriteLn(_name);
              TIdContext(Clist.Items[i]).Connection.IOHandler.WriteLn(IntToStr(_x));
              TIdContext(Clist.Items[i]).Connection.IOHandler.WriteLn(IntToStr(_y));
              TIdContext(Clist.Items[i]).Connection.IOHandler.WriteLn(IntToStr(_z));
            end;
        Except
          On E : Exception do
            myplayer.mychat.add_text('Erreur send_new_client: ' + E.Message);
        end;
      finally
        myplayer.mychat.add_text('send_new_client');
        server.Contexts.UnlockList;
      end;
    end;

  procedure C_server.send_del_client(_name: string);
  var
    CList : TList;
    i : integer;
    begin
      try
        try
          while locked do
          sleep(100);
          CList := server.Contexts.LockList;
          for i := 0 to CList.Count - 1 do
            begin
              TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn('#delclient');
              TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(_name);
            end;
        Except
          On E : Exception do
            myplayer.mychat.add_text('Erreur send_del_client : ' + E.Message);
        end;
      finally
        myplayer.mychat.add_text('send_del_client');
        server.Contexts.UnlockList;
      end;
    end;
  
    procedure c_server.send_ennemi_move(p1, p2, p3, p4, p5, p6 : string);
    var
      i :integer;
      CList : TList;
      begin
        try
          try
            while locked do
              Sleep(100);
            CList := server.contexts.Locklist;
            for i := 0 to CList.Count - 1 do
              begin
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn('#ennmove');
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p1);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p2);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p3);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p4);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p5);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p6);
              end;
          except
            On E : Exception do
              myplayer.mychat.add_text('Erreur envoi ennmove' + E.message);
          end;
        finally
          server.contexts.unlocklist;
        end;
      end;

    procedure c_server.send_ennemi_del_pos(p1, p2, p3 : string);
    var
      i :integer;
      CList : TList;
      begin
        try
          try
            while locked do
              Sleep(100);
            CList := server.contexts.Locklist;
            for i := 0 to CList.Count - 1 do
              begin
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn('#enndelpos');
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p1);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p2);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p3);
              end;
          except
            On E : Exception do
              myplayer.mychat.add_text('Erreur envoi enndelpos' + E.message);
          end;
        finally
          server.contexts.unlocklist;
        end;
      end;

    procedure c_server.send_ennemi_del_ij(p1, p2 : string);
    var
      i :integer;
      CList : TList;
      begin
        try
          try
            while locked do
              Sleep(100);
            CList := server.contexts.Locklist;
            for i := 0 to CList.Count - 1 do
              begin
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn('#enndelij');
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p1);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p2);
              end;
          except
            On E : Exception do
              myplayer.mychat.add_text('Erreur envoi enndelij' + E.message);
          end;
        finally
          server.contexts.unlocklist;
        end;
      end;

    procedure c_server.send_joueur_hit(p1, p2, p3, p4, p5, p6, p7 : string);
    var
      i :integer;
      CList : TList;
      begin
        try
          try
            while locked do
              Sleep(100);
            CList := server.contexts.Locklist;
            for i := 0 to CList.Count - 1 do
              begin
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn('#hitjoueur');
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p1);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p2);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p3);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p4);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p5);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p6);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p7);
              end;
          except
            On E : Exception do
              myplayer.mychat.add_text('Erreur envoi hitjoueur' + E.message);
          end;
        finally
          server.contexts.unlocklist;
        end;
      end;

    procedure c_server.send_new_obj(p1, p2, p3, p4, p5, p6, p7, p8 : string);
    var
      i :integer;
      CList : TList;
      begin
        try
          try
            while locked do
              Sleep(100);
            CList := server.contexts.Locklist;
            for i := 0 to CList.Count - 1 do
              begin
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn('#addobj');
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p1);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p2);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p3);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p4);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p5);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p6);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p7);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p8);
              end;
          except
            On E : Exception do
              myplayer.mychat.add_text('Erreur envoi addobj' + E.message);
          end;
        finally
          server.contexts.unlocklist;
        end;
      end;

    procedure c_server.send_del_obj(p1: string; p2: string; p3: string);
    var
      i :integer;
      CList : TList;
      begin
        try
          try
            while locked do
              Sleep(100);
            CList := server.contexts.Locklist;
            for i := 0 to CList.Count - 1 do
              begin
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn('#delobj');
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p1);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p2);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p3);
              end;
          except
            On E : Exception do
              myplayer.mychat.add_text('Erreur envoi addobj' + E.message);
          end;
        finally
          server.contexts.unlocklist;
        end;
      end;

    procedure c_server.send_new_ennemi(p1, p2, p3, p4, p5, p6 : string);
    var
      i :integer;
      CList : TList;
      begin
        try
          try
            while locked do
              Sleep(100);
            CList := server.Contexts.LockList;
            for i := 0 to CList.Count - 1 do
              begin
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn('newennemi');
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p1);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p2);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p3);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p4);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p5);
                TIdContext(CList.Items[i]).Connection.IOHandler.WriteLn(p6);
              end;
          except
            On E : Exception do
              myplayer.mychat.add_text('Erreur envoi newennemi' + E.Message);
          end;
        finally

        end;
      end;

end.
